package cn.blnp.net.flowable.transfer.gateway.exclusive;

import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * <h3>网关-排他网关案例</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/19 16:15
 */
@Slf4j
@SpringBootTest
public class ExclusiveGatewayTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    /**
     *  <h2>排他网关</h2>
     *  <p>
     *   &emsp;&emsp;排他网关，也称异或（XOR）网关，是BPMN中的常见网关，用于在流程流转中实现分支决策建模。排他网关需要和条件顺序流搭配使用，当流程流转到排他网关时，所有流出的顺序流都会被按顺序求解，
     *   其中第一条条件解析为true的顺序流会被选中（当多条顺序流的条件为true时，只有第一条顺序流会被选中）。<br/>
     *   &emsp;&emsp;此时，流程不再计算其他流出分支，而是沿着被选中的顺序流流转。如果所有顺序流条件计算结果都为false且该网关定义了一个默认顺序流，那么该默认顺序流将被执行。如果所有顺序流条件计算结果
     *   都为false且没有定义默认顺序流，则抛出异常，中断执行（在流程设计时应该避免这种情况，至少确保有一条分支的顺序流计算结果为true）。
     *  </p>
     *  <h3>案例演示</h3>
     *  <p>
     *    &emsp;&emsp;该流程为费用报销流程。排他网关exclusiveGateway1后流出3条分支：如果流程变量variable1的值等于1，则沿“部门经理审批”节点路径流转；如果流程变量variable1的值等于2，则沿“总监审批”节点路径流转；
     *    如果条件都不满足，则沿“直属上级审批”节点路径流转。接下来，如果“部门经理审批”用户任务或“总监审批”用户任务被执行，排他网关exclusiveGateway2将被激活；如果流程变量variable2的值等于1，将沿“财务
     *    经理审批”节点路径流转；如果variable2的值等于2，则沿“财务主管审批”节点路径流转。
     *      <b>流程定义文件：</b>{@link flow/exclusiveGateway.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/19/682aee80ebe94.png" />
     *  </p>
     **/
    @Test
    public void testBase() {
        Deployment deploy = repositoryService.createDeployment()
                .name("排他网关演示案例")
                .addClasspathResource("flow/exclusiveGateway.bpmn20.xml")
                .deploy();
        log.info("部署流程定义：{}", deploy.getId());
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义编号：{}", procDef.getId());
        //设置流程变量
        Map<String, Object> varMap = MapUtil.builder(new HashMap<String, Object>())
                .put("variable1", 1)
                .build();
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(procDef.getId(), varMap);
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());

        //查询任务
        Task task1 = taskQuery.singleResult();
        log.info("流程发起后，第一个用户任务的名称：{}", task1.getName());
        //设置variable2变量值
        Map<String, Object> varMap2= MapUtil.builder(new HashMap<String, Object>())
                .put("variable2", 2)
                .build();
        //完成任务
        taskService.complete(task1.getId(), varMap2);
        //查询任务
        Task task2 = taskQuery.singleResult();
        log.info("第一个任务提交后，流程当前所在的用户任务的名称：{}", task2.getName());
        //完成任务
        taskService.complete(task2.getId());

        /**
         *  演示结果：
         *  2025-05-19 16:45:37.355  INFO 35728 --- [           main] c.b.n.f.t.g.e.ExclusiveGatewayTest       : 部署流程定义：a24d401d-348d-11f0-b1bf-50ebf6ec8f6d
         * 2025-05-19 16:45:37.359  INFO 35728 --- [           main] c.b.n.f.t.g.e.ExclusiveGatewayTest       : 流程定义编号：exclusiveGateway:1:a2b1f560-348d-11f0-b1bf-50ebf6ec8f6d
         * 2025-05-19 16:45:37.454  INFO 35728 --- [           main] c.b.n.f.t.g.e.ExclusiveGatewayTest       : 流程发起后，第一个用户任务的名称：部门经理审批
         * 2025-05-19 16:45:37.504  INFO 35728 --- [           main] c.b.n.f.t.g.e.ExclusiveGatewayTest       : 第一个任务提交后，流程当前所在的用户任务的名称：财务主管审批
         **/
    }
}
